The Lambda Caclulus is the standard model used for studying and implementing functional programming languages. It is a good model because it is small and simple but still Turing complete and easy to extend. Below we sketch a definition of the language at a high level and give evidence for its Turing completeness. In a follow up, we will pin down some details around substitution, the key mechanism for evaluating lambda calculus programs, and detail an implementation of the lambda calculus in Lean.
Lambda calculus programs are composed of (1) variables, (2) applications (i.e., function calls), and (3) abstractions (i.e., function definitions). We define the syntax of lambda calculus with the following BNF grammar:
e ::= x // variable | e e // function application | λ x . e // function definition
Let's look at some syntactic examples:
Notice how these two programs only differ in the name that the variable happens to have. Later we will argue that these programs are really equivalent since they only differ in how variables are named.
We use some conventions when writing out lambda calculus terms ("terms" just means programs), to avoid needing a bunch of parentheses:
As a final detail, we will also define a subset of lambda terms called "values" which we think of as programs that are "done executing" (this will be useful in the semantics below and for defining notions like "getting stuck"):
OK, now we know what lambda calculus programs are, but not what they mean. Here we'll give a "call-by-value", left-to-right, small step operational semantics:
Repeated with some commentary:
Notice how we've designed the rules so there is at most one point where you can make progress on evaluating a term. Also notice how the only thing we can evaluate are applications: the left hand side of every arrow is an APP!
Let's see some examples:
There are even some terms which we can keep on evaluating forever:
Since the step relation "-->" only shows how a term can take a single step, we'll often want to consider its reflexive, transitive closure "-->*":
To aid exposition, we'll be a little be loose when we write derivations by hand. A single "-->" may actually mean "-->*", and
we may fudge the rules a bit on evaluation order. When we treat the lambda calculus formally in Lean, all these issues will be made completely precise.
At the top, we claimed that lambda calculus is Turing complete, but so far we've only seen stuff about "grind on the left, grind on the right, substitute"... so when do we get to the actual programming language part? Turns out, we're already done, but it can be hard to see. To illustrate how the lambda calculus as it stands above is already Turing complete, we'll show who to encode several useful programming constructs building from booleans up.
First though, a note on what it means for a language to "support" a feature. Here we'll consider features as abstract data types. Essentially this means that we will describe how values of a particular sort can be created ("introduced") and used ("eliminated").
An ADT for booleans in the lambda calculus:
and the same with some commentary:
A couple sanity checks:
This version of booleans is just find, but note that we have to be a little careful using cond
since while sometimes it works like in normal programming (for arbitrary values v1 v2
):
Notice that things do NOT match "normal" programming if one of the arguments to cond
is non-terminating:
We can address this by using "thunks", which will need to do below when we consider recursion.
Pairs are pretty straightforward; we just need (1) a way to take two things and "put them in a pair", (2) given a pair, a way to get the first thing out, and (3) given a pair, a way to get the second things out. One way to do this in lambda calculus is:
Some hand-wavy examples with arbitrary values v1 v2 v3
:
One interesting coincidence: fst
is the same as true
and snd
is the same as false
. This is not a problem for us,
any more than it's a problem for the bit pattern 0b00000000000000000000000000000000
to indicate both integer and floating point 0
in 32-bit x86 assembly. Remember: the syntax only has the meaning we give it! Here we're providing the operations for ADTs so that they provide mechanisms similar to what we're used to in "normal" programming languages.
With booleans and pairs, we have enough to implement a list ADT. We'll use nested pairs for lists, with the additional detail that we "tag" each cell to indicate whether it is a "cons" or "nil" cell. These tags are essential since otherwise we would not be able to implement functions like is_empty
.
To visualize some simple, hand wavy examples for values v1 v2
:
Notice how all lists are pairs where the first element is a boolean indicating whether the list is empty. Non-empty lists are a pair where the first element is true
and the second element is another pair P such that the first element of P
is the "first element of the list" and the second element of P is the tail of the list. Empty lists are also a pair, but the first element is false
and it does not matter what the second element is, though here we have used false
as a convenient dummy value.
Given this list representation, we can encode some functions over list as well:
Note that tail nil
does some weird stuff, but that's OK: the user should never call tail
on an empty list, it breaks the contract. Taking the tail of an empty list is like dereferencing a null pointer in C/C++/Java.
We encode the natural number n as a function which takes two arguments and applies the first n times starting with the second:
Note that this is very similar to the way that we defined natural numbers in Lean:
Some functions on numbers:
Sanity check examples starts to get pretty tedious once we have numbers...
So far we've built up booleans, pairs, lists, and natrual numbers. These features can be composed to build all sorts of other datastructures. For example we can encode strings as lists of numbers where each character is represented by its ASCII enconding or represent integers by pairs of a sign bit (boolean) and a natural number (would need to be careful about "signed zero" issues with that choice though!), etc. Hopefully the above is enough to convince you that, with sufficient effort, we can encode pretty much any type we're used in "normal" programming. There is one feature that's not obvious yet though...
How do we get recursion in lambda calculus? It seems like a real chicken and egg problem: in order for a function to call itself, it must first be defined, right? Compilers can help us out in normal programming languages by resolving the functions called in a body after the function is defined. What are we to do in lambda calculus though? Do we need to introduce an explicit notion of environment as we did in IMP? It turns out the answer is "no".
The "Y combinator" is one of many fixed-point combinators we can use to get recursion in the lambda calculus. This one works on the principle of passing a function itself as it's first argument. Thus, if we want to write a recursive function foo
, we arrange for foo
to take another function as its first argument. Then, when we apply Y
to foo
, it will reduce to foo foo
, thus providing foo
a reference to itself and enabling recursion.
That all sounds a bit strange, so let's consider an example: factorial
. Here is one version of factorial
designed to work with Y
:
How does Y
manage this feat? Let's walk through it. First the definition:
Let's see what Y g
is for some arbitrary value g
:
OK, now for a very hand wavy example:
There are several things VERY WRONG with the above "squiggly" example: we are not strictly evaluating left-to-right, we are evaluating implicitly under lambdas, and we are not being strict about how cond
works with respect to termination. Hopefully, the above handwave helps your intuition though.
If we want to do this example "for real", i.e., in full detail, it looks like:
(((λf. ((λx. (f (λv. ((x x) v)))) (λx. (f (λv. ((x x) v)))))) (λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x)))))) (λs. (λz. (s (s z))))) (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) (λs. (λz. (s (s z))))) (((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v))) (λs. (λz. (s (s z))))) ((λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x)))) (λs. (λz. (s (s z))))) ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) (λs. (λz. (s (s z)))))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) ((((λb. (λp. (λq. ((b p) q)))) (((λs. (λz. (s (s z)))) (λx. (λx. (λy. y)))) (λx. (λy. x)))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) ((((λb. (λp. (λq. ((b p) q)))) ((λz. ((λx. (λx. (λy. y))) ((λx. (λx. (λy. y))) z))) (λx. (λy. x)))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) ((((λb. (λp. (λq. ((b p) q)))) ((λx. (λx. (λy. y))) ((λx. (λx. (λy. y))) (λx. (λy. x))))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) ((((λb. (λp. (λq. ((b p) q)))) ((λx. (λx. (λy. y))) (λx. (λy. y)))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) ((((λb. (λp. (λq. ((b p) q)))) (λx. (λy. y))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) (((λp. (λq. (((λx. (λy. y)) p) q))) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) ((λq. (((λx. (λy. y)) (λx. ((λs. (λz. (s z))) x))) q)) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) (((λx. (λy. y)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) ((λy. y) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) (λs. (λz. (s (s z))))) ((λv. (((λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v)))) (λx. ((λf. (λn. ((((λb. (λp. (λq. ((b p) q)))) ((λn. ((n (λx. (λx. (λy. y)))) (λx. (λy. x)))) n)) (λx. ((λs. (λz. (s z))) x))) (λx. ((((λm. (λn. ((m ((λm. (λn. ((m (λn. (λs. (λz. (s ((n s) z)))))) n))) n)) (λs. (λz. z))))) n) (f ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) n))) x))))) (λv. ((x x) v))))) v)) ((λn. ((λp. (p (λx. (λy. y)))) ((n (λp. ((λn. (((λx. (λy. (λs. ((s x) y)))) ((λn. (λs. (λz. (s ((n s) z))))) n)) n)) ((λp. (p (λx. (λy. x)))) p)))) (((λx. (λy. (λs. ((s x) y)))) (λs. (λz. z))) (λs. (λz. z)))))) (λs. (λz. (s (s z))))))) x)) DONE. (λx. (λz. (x (x z))))
Getting this output requires fixing our definition of fact
to be:
Here's the OCaml code for getting detailed traces of reductions:
type e =| Var of string| App of e * e| Abs of string * elet rec str = function| Var x ->x| App (e1, e2) ->Printf.sprintf "(%s %s)"(str e1)(str e2)| Abs (x, e) ->Printf.sprintf "(λ%s. %s)" x(str e)let isval = function| Var _ -> false| App _ -> false| Abs _ -> truelet rec subst e v x =match e with| Var y ->if x = ythen velse e| App (e1, e2) ->App (subst e1 v x, subst e2 v x)| Abs (y, e') ->if x = ythen eelse Abs (y, subst e' v x)let rec step = function| Var _ ->failwith "stuck: cannot step var"| App (Abs (x, e1), e2) ->if isval e2 thensubst e1 e2 xelseApp (Abs (x, e1), step e2)| App (e1, e2) ->App (step e1, e2)| Abs _ ->failwith "done: cannot step abstraction"let rec sstep = function| Var x ->Var x| App (Abs (x, e1), e2) ->subst e1 e2 x| App (e1, e2) ->App (sstep e1, sstep e2)| Abs (x, e) ->Abs (x, sstep e)let rec simp e =let e' = sstep e inif e = e'then e'else simp e'let rec trace ?simplify:(simplify = true) e =Printf.printf "%s\n\n" (str e);if isval e then beginprint_string "DONE.\n\n";begin if simplify thenPrintf.printf "%s\n\n" (str (simp e))endend elsetrace ~simplify:simplify (step e)let lcID =Abs ("x", Var "x")let lcTRUE =Abs ("x", Abs ("y", Var "x"))let lcFALSE =Abs ("x", Abs ("y", Var "y"))let lcCOND =Abs ("b", Abs ("p", Abs ("q",App (App (Var "b", Var "p"), Var "q"))))let lcNOT =Abs ("a", App (App (Var "a", lcFALSE), lcTRUE))let lcAND =Abs ("a", Abs ("b",App (App (Var "a", Var "b"), lcFALSE)))let lcOR =Abs ("a", Abs ("b",App (App (Var "a", lcTRUE), Var "b")))let lcOMEGA =App ( Abs ("x", App (Var "x", Var "x")), Abs ("x", App (Var "x", Var "x")))let lcMKPAIR =Abs ("x", Abs ("y", Abs ("s",App (App (Var "s", Var "x"), Var "y"))))let lcFST =Abs ("p", App (Var "p", lcTRUE))let lcSND =Abs ("p", App (Var "p", lcFALSE))let lcNIL =App (App (lcMKPAIR, lcFALSE), lcFALSE)let lcCONS =Abs ("h", Abs ("t",App ( App (lcMKPAIR, lcTRUE), App (App (lcMKPAIR, Var "h"), Var "t"))))let lcISEMPTY =Abs ("l", App (lcFST, Var "l"))let lcHEAD =Abs ("l", App (lcFST, App (lcSND, Var "l")))let lcTAIL =Abs ("l", App (lcSND, App (lcSND, Var "l")))let lcZERO =Abs ("s", Abs ("z", Var "z"))let lcSUCC =Abs ("n", Abs ("s", Abs ("z",App (Var "s", (App (App (Var "n", Var "s"), Var "z"))))))(*\p. mkpair (succ (fst p)) (fst p)\p. (\n. mkpair (succ n) n) (fst p)*)let lcPREDaux =Abs ("p",App ( Abs ("n",App (App (lcMKPAIR, App (lcSUCC, Var "n")), Var "n")), App (lcFST, Var "p")))let lcPRED =Abs ("n",App (lcSND, App (App (Var "n", lcPREDaux),App (App (lcMKPAIR, lcZERO), lcZERO))))let lcMKNUM n =let rec loop i =if i <= 0then Var "z"else App (Var "s", loop (i - 1))inAbs ("s", Abs ("z", loop n))let lcONE =lcMKNUM 1let lcTWO =lcMKNUM 2let lcTHREE =lcMKNUM 3let lcISZERO =Abs ("n",App (App (Var "n", Abs ("x", lcFALSE)), lcTRUE))let lcADD =Abs ("m", Abs ("n",App (App (Var "m", lcSUCC), Var "n")))let lcMUL =Abs ("m", Abs ("n",App (App (Var "m", App (lcADD, Var "n")), lcZERO)))let lcPOW =Abs ("m", Abs ("n",App (App (Var "n", App (lcMUL, Var "m")), lcONE)))let lcSUB =Abs ("m", Abs ("n",App (App (Var "n", lcPRED), Var "m")))let lcTHUNK t =Abs ("x", App (t, Var "x"))let lcFACT =Abs ("f", Abs ("n",App ( App (App (lcCOND, App (lcISZERO, Var "n")), lcTHUNK lcONE), lcTHUNK (App (App (lcMUL, Var "n"), App (Var "f", App (lcPRED, Var "n")))))))let lcY =Abs ("f",App ( Abs ("x", App (Var "f",Abs ("v", App (App (Var "x", Var "x"), Var "v")))), Abs ("x", App (Var "f",Abs ("v", App (App (Var "x", Var "x"), Var "v"))))))let _ = trace ~simplify:true (App (App (lcY, lcFACT), lcTWO))(*App (lcY, lcFACT)App (App (lcSUB, lcMKNUM 3), lcMKNUM 2)App (App (lcSUB, lcMKNUM 2), lcMKNUM 3)App (lcPRED, lcTHREE)App (lcISZERO, lcONE)App (lcISZERO, lcZERO)App (lcTAIL, App (App (lcCONS, lcZERO), lcNIL))App (lcHEAD, App (App (lcCONS, lcZERO), lcNIL))App (App (lcCONS, lcZERO), lcNIL)App (lcSND, App (App (lcMKPAIR, lcTRUE), lcFALSE))App (App (App (lcCOND, lcTRUE), lcTRUE), lcOMEGA)lcOMEGAApp (App (lcOR, lcTRUE), lcFALSE)App (App (lcMUL, lcMKNUM 2), lcMKNUM 3)App (App (lcPOW, lcMKNUM 2), lcMKNUM 3)(Abs ("x", Var "x"))(App ( Abs ("x", Var "x"), Abs ("x", Var "x")))*)